/*
 * NESState.cpp
 *
 *  Created on: Oct 27, 2012
 *      Author: nam20485
 */

#include "NESState.h"
#include "Arduino.h"

// pre-amble to alert NES MCU that we want to start reading buttons
void NESState::initialize()
{
	// set each pin's mode and then high
	pinMode(DATA_PIN, INPUT);
	digitalWrite(DATA_PIN, HIGH);

	pinMode(LATCH_PIN, OUTPUT);
	digitalWrite(LATCH_PIN, HIGH);

	pinMode(CLOCK_PIN, OUTPUT);
	digitalWrite(CLOCK_PIN, HIGH);
}

bool NESState::refresh()
{
	m_state = 0;

	// protect state refresh with critical section, block button pressed read until
	digitalWrite(LATCH_PIN, LOW);

	if (readNextBit())	m_state |= A;
	if (readNextBit())	m_state |= B;
	if (readNextBit())	m_state |= SELECT;
	if (readNextBit())	m_state |= START;
	if (readNextBit())	m_state |= UP;
	if (readNextBit())	m_state |= DOWN;
	if (readNextBit())	m_state |= LEFT;
	if (readNextBit())	m_state |= RIGHT;

	digitalWrite(LATCH_PIN, HIGH);

	return (m_state != 0);
}

bool NESState::readNextBit() const
{
	// is button on if signal is low or high?
	bool high = digitalRead(DATA_PIN);	// high is being used
	digitalWrite(CLOCK_PIN, LOW);
	digitalWrite(CLOCK_PIN, HIGH);

	return (! high);	// active low
}

#ifdef _GAMEPADREPORT

void NESState::createGamepadReport(USB_GamepadReport_Data_t& gamepadReport) const
{
	if (buttonIsPressed(NESState::A))		gamepadReport.buttons |= (1<<0);
	if (buttonIsPressed(NESState::B))		gamepadReport.buttons |= (1<<1);
	if (buttonIsPressed(NESState::SELECT))	gamepadReport.buttons |= (1<<2);
	if (buttonIsPressed(NESState::START))	gamepadReport.buttons |= (1<<3);

	if (buttonIsPressed(NESState::UP))		gamepadReport.y = 0;
	if (buttonIsPressed(NESState::DOWN))	gamepadReport.y = 0;

	if (buttonIsPressed(NESState::LEFT))	gamepadReport.x = 0;
	if (buttonIsPressed(NESState::RIGHT))	gamepadReport.x = 0;
}

#endif /* NESSTATE_H_ */
